﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using INDEX = System.UInt64;

namespace Library.Linq
{
    public static class Enumerable
    {
        internal class OrderByEnumerable<TSource, TKey> : IOrderedEnumerable<TSource>,
            Library.Collections.Generic.IContainer<TSource>,
            Library.Collections.ICountable,
            IDistinct<TSource>,
            IQuantifiable<TSource>,
            IReverse<TSource>
        {
            public static IOrderedEnumerable<TSource> Create(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector)
            {
                return new OrderByEnumerable<TSource, TKey>(input, keySelector);
            }
            public static IOrderedEnumerable<TSource> Create(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer)
            {
                return new OrderByEnumerable<TSource, TKey>(input, keySelector, comparer);
            }

            OrderByEnumerable(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector)
            {
                this.input = input;
                this.keySelector = keySelector;
                this.comparer = null;
            }
            OrderByEnumerable(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer)
            {
                this.input = input;
                this.keySelector = keySelector;
                this.comparer = comparer;
            }

            IEnumerable<TSource> input;
            Expression<Func<TSource, TKey>> keySelector;
            IComparer<TKey> comparer;
            Expression<Func<TSource, TSource, int>> comparison;

            IEnumerable IOrderedEnumerable.Input
            {
                get { return input; }
            }

            public LambdaExpression KeySelector
            {
                get { return keySelector; }
            }

            public IComparer Comparer
            {
                get
                {
                    if (comparer == null) return null;
                    IComparer _comparer = comparer as IComparer;
                    if (_comparer != null)
                        return _comparer;
                    return new Library.Collections.Specialized.Comparer<TKey>(comparer);
                }
            }

            public LambdaExpression Comparison
            {
                get
                {
                    if (comparison == null)
                    {
                        var x = Expression.Variable(typeof(TSource));
                        var y = Expression.Variable(typeof(TSource));

                        Expression key1 = Expression.Invoke(keySelector, x);
                        Expression key2 = Expression.Invoke(keySelector, y);

                        if (comparer != null)
                        {
                            comparison = Expression.Lambda<Func<TSource, TSource, int>>(Expression.Call(Expression.Constant(comparer), typeof(IComparer<TKey>).GetMethod("Compare"), key1, key2), x, y);
                        }
                        else
                        {
                            if (typeof(IComparable<TKey>).IsAssignableFrom(typeof(TKey)))
                            {
                                var method = typeof(IComparable<TKey>).GetMethod("CompareTo");
                                comparison = Expression.Lambda<Func<TSource, TSource, int>>(Expression.Call(key1, method, key2), x, y);
                            }
                            else
                            {
                                comparison = Expression.Lambda<Func<TSource, TSource, int>>(Expression.Call(Expression.Constant(Comparer<TKey>.Default), typeof(Comparer<TKey>).GetMethod("Compare"), key1, key2), x, y);
                            }
                        }
                    }
                    return comparison;
                }
            }

            public IEnumerator<TSource> GetEnumerator()
            {
                if (comparer == null)
                {
                    return System.Linq.Queryable.OrderBy(input.AsQueryable(), keySelector).GetEnumerator();
                }
                else
                {
                    return System.Linq.Queryable.OrderBy(input.AsQueryable(), keySelector, comparer).GetEnumerator();
                }
            }
            IEnumerator IEnumerable.GetEnumerator()
            {
                if (comparer == null)
                {
                    return System.Linq.Queryable.OrderBy(input.AsQueryable(), keySelector).GetEnumerator();
                }
                else
                {
                    return System.Linq.Queryable.OrderBy(input.AsQueryable(), keySelector, comparer).GetEnumerator();
                }
            }

            public bool Contains(TSource item)
            {
                if(input != null)
                    return input.Contains(item);
                return System.Linq.Enumerable.Contains(this, item);
            }

            public INDEX Count
            {
                get { return input.Count(); }
            }

            public bool IsDistinct(out bool value)
            {
                IDistinct<TSource> distinct = input as IDistinct<TSource>;
                if (distinct != null)
                    return distinct.IsDistinct(out value);

                value = false;
                return false;
            }

            public IEnumerable<TSource> Distinct()
            {
                IDistinct<TSource> distinct = input as IDistinct<TSource>;
                if (distinct != null)
                    return distinct.Distinct();

                return System.Linq.Enumerable.Distinct<TSource>(this);
            }

            public IEnumerable<TSource> Distinct(IEqualityComparer<TSource> comparer)
            {
                IDistinct<TSource> distinct = input as IDistinct<TSource>;
                if (distinct != null)
                    return distinct.Distinct(comparer);

                return System.Linq.Enumerable.Distinct<TSource>(this, comparer);
            }

            public bool ForAll(Func<TSource, bool> predicate)
            {
                return input.All(predicate);
            }

            public bool Exists()
            {
                return input.Any();
            }

            public bool Exists(Func<TSource, bool> predicate)
            {
                return input.Any(predicate);
            }

            public IEnumerable<TSource> Reverse()
            {
                return OrderByDescendingEnumerable<TSource, TKey>.Create(input, keySelector, comparer);
            }
        }
        internal class OrderByDescendingEnumerable<TSource, TKey> : IOrderedEnumerable<TSource>,
            Library.Collections.Generic.IContainer<TSource>,
            Library.Collections.ICountable,
            IDistinct<TSource>,
            IQuantifiable<TSource>,
            IReverse<TSource>
        {
            public static IOrderedEnumerable<TSource> Create(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector)
            {
                return new OrderByDescendingEnumerable<TSource, TKey>(input, keySelector);
            }
            public static IOrderedEnumerable<TSource> Create(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer)
            {
                return new OrderByDescendingEnumerable<TSource, TKey>(input, keySelector, comparer);
            }

            OrderByDescendingEnumerable(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector)
            {
                this.input = input;
                this.keySelector = keySelector;
                this.comparer = null;
            }
            OrderByDescendingEnumerable(IEnumerable<TSource> input, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer)
            {
                this.input = input;
                this.keySelector = keySelector;
                this.comparer = comparer;
            }

            IEnumerable<TSource> input;
            Expression<Func<TSource, TKey>> keySelector;
            IComparer<TKey> comparer;
            Expression<Func<TSource, TSource, int>> comparison;

            IEnumerable IOrderedEnumerable.Input
            {
                get { return input; }
            }

            public LambdaExpression KeySelector
            {
                get { return keySelector; }
            }

            public IComparer Comparer
            {
                get
                {
                    if (comparer == null) return null;
                    IComparer _comparer = comparer as IComparer;
                    if (_comparer != null)
                        return _comparer;
                    return new Library.Collections.Specialized.Comparer<TKey>(comparer);
                }
            }

            public LambdaExpression Comparison
            {
                get
                {
                    if (comparison == null)
                    {
                        var x = Expression.Variable(typeof(TSource));
                        var y = Expression.Variable(typeof(TSource));

                        Expression key1 = Expression.Invoke(keySelector, x);
                        Expression key2 = Expression.Invoke(keySelector, y);

                        if (comparer != null)
                        {
                            comparison = Expression.Lambda<Func<TSource, TSource, int>>(Expression.Call(Expression.Constant(comparer), typeof(IComparer<TKey>).GetMethod("Compare"), key2, key1), x, y);
                        }
                        else
                        {
                            if (typeof(IComparable<TKey>).IsAssignableFrom(typeof(TKey)))
                            {
                                var method = typeof(IComparable<TKey>).GetMethod("CompareTo");
                                comparison = Expression.Lambda<Func<TSource, TSource, int>>(Expression.Call(key1, method, key2), x, y);
                            }
                            else
                            {
                                comparison = Expression.Lambda<Func<TSource, TSource, int>>(Expression.Call(Expression.Constant(Comparer<TKey>.Default), typeof(Comparer<TKey>).GetMethod("Compare"), key2, key1), x, y);
                            }
                        }
                    }
                    return comparison;                
                }
            }

            public IEnumerator<TSource> GetEnumerator()
            {
                if (comparer == null)
                {
                    return System.Linq.Queryable.OrderByDescending(input.AsQueryable(), keySelector).GetEnumerator();
                }
                else
                {
                    return System.Linq.Queryable.OrderByDescending(input.AsQueryable(), keySelector, comparer).GetEnumerator();
                }
            }
            IEnumerator IEnumerable.GetEnumerator()
            {
                if (comparer == null)
                {
                    return System.Linq.Queryable.OrderByDescending(input.AsQueryable(), keySelector).GetEnumerator();
                }
                else
                {
                    return System.Linq.Queryable.OrderByDescending(input.AsQueryable(), keySelector, comparer).GetEnumerator();
                }
            }

            public bool Contains(TSource item)
            {
                if (input != null)
                    return input.Contains(item);
                return System.Linq.Enumerable.Contains(this, item);
            }

            public INDEX Count
            {
                get { return input.Count(); }
            }

            public bool IsDistinct(out bool value)
            {
                IDistinct<TSource> distinct = input as IDistinct<TSource>;
                if (distinct != null)
                    return distinct.IsDistinct(out value);

                value = false;
                return false;
            }

            public IEnumerable<TSource> Distinct()
            {
                IDistinct<TSource> distinct = input as IDistinct<TSource>;
                if (distinct != null)
                    return distinct.Distinct();

                return System.Linq.Enumerable.Distinct<TSource>(this);
            }

            public IEnumerable<TSource> Distinct(IEqualityComparer<TSource> comparer)
            {
                IDistinct<TSource> distinct = input as IDistinct<TSource>;
                if (distinct != null)
                    return distinct.Distinct(comparer);

                return System.Linq.Enumerable.Distinct<TSource>(this, comparer);
            }

            public bool ForAll(Func<TSource, bool> predicate)
            {
                return input.All(predicate);
            }

            public bool Exists()
            {
                return input.Any();
            }

            public bool Exists(Func<TSource, bool> predicate)
            {
                return input.Any(predicate);
            }

            public IEnumerable<TSource> Reverse()
            {
                return OrderByEnumerable<TSource, TKey>.Create(input, keySelector, comparer);
            }
        }

        static IOrderedEnumerable<TSource> CreateThenBy<TSource, TKey>(IOrderedEnumerable<TSource> input, Func<TSource, TKey> keySelector)
        {
            throw new System.NotImplementedException();
        }
        static IOrderedEnumerable<TSource> CreateThenBy<TSource, TKey>(IOrderedEnumerable<TSource> input, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            throw new System.NotImplementedException();
        }
        static IOrderedEnumerable<TSource> CreateThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource> input, Func<TSource, TKey> keySelector)
        {
            throw new System.NotImplementedException();
        }
        static IOrderedEnumerable<TSource> CreateThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource> input, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            throw new System.NotImplementedException();
        }



        public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Aggregate<TSource>(queryable, (x, y) => func(x, y));

            IAggregate<TSource> aggregatable = source as IAggregate<TSource>;
            if (aggregatable != null)
                return aggregatable.Aggregate(func);

            return System.Linq.Enumerable.Aggregate(source, func);
        }
        public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Aggregate<TSource, TAccumulate>(queryable, seed, (x, y) => func(x, y));

            IAggregate<TSource> aggregatable = source as IAggregate<TSource>;
            if (aggregatable != null)
                return aggregatable.Aggregate<TAccumulate>(seed, func);

            return System.Linq.Enumerable.Aggregate(source, seed, func);
        }
        public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(queryable, seed, (x, y) => func(x, y), (x) => resultSelector(x));

            IAggregate<TSource> aggregatable = source as IAggregate<TSource>;
            if (aggregatable != null)
                return aggregatable.Aggregate<TAccumulate, TResult>(seed, func, resultSelector);

            return System.Linq.Enumerable.Aggregate(source, seed, func, resultSelector);
        }
        public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.All<TSource>(queryable, (x) => predicate(x));

            IQuantifiableLambdaExpression<TSource> container2 = source as IQuantifiableLambdaExpression<TSource>;
            if (container2 != null)
                return container2.ForAll((x) => predicate(x));

            IQuantifiable<TSource> container = source as IQuantifiable<TSource>;
            if (container != null)
                return container.ForAll(predicate);

            return System.Linq.Enumerable.All(source, predicate);
        }
        public static bool Any<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Any<TSource>(queryable);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
                return countable.Count > 0;

            return System.Linq.Enumerable.Any(source);
        }
        public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Any<TSource>(queryable, (x) => predicate(x));

            IQuantifiableLambdaExpression<TSource> container2 = source as IQuantifiableLambdaExpression<TSource>;
            if (container2 != null)
                return container2.Exists((x) => predicate(x));

            IQuantifiable<TSource> container = source as IQuantifiable<TSource>;
            if (container != null)
                return container.Exists(predicate);

            return System.Linq.Enumerable.Any(source, predicate);
        }
        public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
        {
            return source;
        }
        public static decimal? Average(this IEnumerable<decimal?> source)
        {
            System.Linq.IQueryable<decimal?> queryable = source as System.Linq.IQueryable<decimal?>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<decimal?>(queryable, x => x);

            decimal? item;
            IAverage<decimal?> average = source as IAverage<decimal?>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static decimal Average(this IEnumerable<decimal> source)
        {
            System.Linq.IQueryable<decimal> queryable = source as System.Linq.IQueryable<decimal>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<decimal>(queryable, x => x);

            decimal item;
            IAverage<decimal> average = source as IAverage<decimal>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static double? Average(this IEnumerable<double?> source)
        {
            System.Linq.IQueryable<double?> queryable = source as System.Linq.IQueryable<double?>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<double?>(queryable, x => x);

            double? item;
            IAverage<double?> average = source as IAverage<double?>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static double Average(this IEnumerable<double> source)
        {
            System.Linq.IQueryable<double> queryable = source as System.Linq.IQueryable<double>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<double>(queryable, x => x);
            
            double item;
            IAverage<double> average = source as IAverage<double>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static float? Average(this IEnumerable<float?> source)
        {
            System.Linq.IQueryable<float?> queryable = source as System.Linq.IQueryable<float?>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<float?>(queryable, x => x);

            float? item;
            IAverage<float?> average = source as IAverage<float?>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static float Average(this IEnumerable<float> source)
        {
            System.Linq.IQueryable<float> queryable = source as System.Linq.IQueryable<float>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<float>(queryable, x => x);

            float item;
            IAverage<float> average = source as IAverage<float>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static double? Average(this IEnumerable<int?> source)
        {
            System.Linq.IQueryable<int?> queryable = source as System.Linq.IQueryable<int?>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<int?>(queryable, x => x);

            double? item;
            IAverage<double?> average = source as IAverage<double?>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static double Average(this IEnumerable<int> source)
        {
            System.Linq.IQueryable<int> queryable = source as System.Linq.IQueryable<int>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<int>(queryable, x => x);

            double item;
            IAverage<double> average = source as IAverage<double>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static double? Average(this IEnumerable<long?> source)
        {
            System.Linq.IQueryable<long?> queryable = source as System.Linq.IQueryable<long?>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<long?>(queryable, x => x);

            double? item;
            IAverage<double?> average = source as IAverage<double?>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static double Average(this IEnumerable<long> source)
        {
            System.Linq.IQueryable<long> queryable = source as System.Linq.IQueryable<long>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<long>(queryable, x => x);

            double item;
            IAverage<double> average = source as IAverage<double>;
            if (average != null)
                if (average.Average(out item)) return item;

            return System.Linq.Enumerable.Average(source);
        }
        public static decimal? Average<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static decimal Average<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static double? Average<TSource>(this IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static float? Average<TSource>(this IEnumerable<TSource> source, Func<TSource, float?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static float Average<TSource>(this IEnumerable<TSource> source, Func<TSource, float> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static double? Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static double? Average<TSource>(this IEnumerable<TSource> source, Func<TSource, long?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, long> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Average<TSource>(queryable, x => selector(x));

            return System.Linq.Enumerable.Average(source, selector);
        }
        public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
        {
            System.Linq.IQueryable queryable = source as System.Linq.IQueryable;
            if (queryable != null)
                return Library.Linq.Queryable.Cast<TResult>(queryable);

            ICast cast = source as ICast;
            if (cast != null)
                return cast.Cast<TResult>();

            return System.Linq.Enumerable.Cast<TResult>(source);
        }
        public static IEnumerable<TSource> Concat<TSource>(TSource first, TSource second)
        {
            yield return first;
            yield return second;
        }
        public static IEnumerable<TSource> Concat<TSource>(TSource first, IEnumerable<TSource> second)
        {
            yield return first;
            foreach (var item in second)
                yield return item;
        }
        public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, TSource second)
        {
            foreach (var item in first)
                yield return item;
            yield return second;
        }
        public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Concat<TSource>(queryable, second);

            IConcat<TSource> concat = first as IConcat<TSource>;
            if (concat != null)
                return concat.Concat(second);

            return System.Linq.Enumerable.Concat(first, second);
        }
        public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return queryable.Contains(value);

            Library.Collections.Generic.IContainer<TSource> container1 = source as Library.Collections.Generic.IContainer<TSource>;
            if (container1 != null)
                return container1.Contains(value);

            Library.Collections.IContainer container = source as Library.Collections.IContainer;
            if (container != null)
                return container.Contains(value);

            return System.Linq.Enumerable.Contains(source, value);
        }
        public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Contains<TSource>(queryable, value, comparer);

            IContains<TSource> contains = source as IContains<TSource>;
            if (contains != null)
                return contains.Contains(value, comparer);

            return System.Linq.Enumerable.Contains(source, value, comparer);
        }
        public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> source2)
        {
            Library.Collections.Specialized.IContainerBulk<TSource> container = source as Library.Collections.Specialized.IContainerBulk<TSource>;
            if (container != null)
                return container.ContainsAll(source2);

            System.Collections.Generic.ISet<TSource> set = source as System.Collections.Generic.ISet<TSource>;
            if (set != null)
                return set.IsSupersetOf(source2);

            foreach (var item in source2)
                if (!source.Contains(item)) return false;

            return true;
        }
        public static bool ContainsAny<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> source2)
        {
            Library.Collections.Specialized.IContainerBulk<TSource> container = source as Library.Collections.Specialized.IContainerBulk<TSource>;
            if (container != null)
                return container.ContainsAny(source2);

            System.Collections.Generic.ISet<TSource> set = source as System.Collections.Generic.ISet<TSource>;
            if (set != null)
                return set.Overlaps(source2);

            foreach (var item in source2)
                if (source.Contains(item)) return true;

            return false;
        }
        public static bool ContainsNone<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> source2)
        {
            Library.Collections.Specialized.IContainerBulk<TSource> container = source as Library.Collections.Specialized.IContainerBulk<TSource>;
            if (container != null)
                return container.ContainsAny(source2);

            System.Collections.Generic.ISet<TSource> set = source as System.Collections.Generic.ISet<TSource>;
            if (set != null)
                return !set.Overlaps(source2);

            foreach (var item in source2)
                if (source.Contains(item)) return false;

            return true;
        }
        public static INDEX Count<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return (INDEX)Library.Linq.Queryable.Count<TSource>(queryable);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
                return countable.Count;

            return (INDEX)System.Linq.Enumerable.Count(source);
        }
        public static INDEX Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return (INDEX)Library.Linq.Queryable.Count<TSource>(queryable, x => predicate(x));

            return source.Where(predicate).Count();
        }
        public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.DefaultIfEmpty<TSource>(queryable);

            return System.Linq.Enumerable.DefaultIfEmpty(source);
        }
        public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.DefaultIfEmpty<TSource>(queryable, defaultValue);

            return System.Linq.Enumerable.DefaultIfEmpty(source, defaultValue);
        }
        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Distinct<TSource>(queryable);

            IDistinct<TSource> distinct = source as IDistinct<TSource>;
            if (distinct != null)
            {
                return distinct.Distinct();
            }

            return System.Linq.Enumerable.Distinct(source);
        }
        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Distinct<TSource>(queryable, comparer);

            IDistinct<TSource> distinct = source as IDistinct<TSource>;
            if (distinct != null)
            {
                return distinct.Distinct(comparer);
            }

            return System.Linq.Enumerable.Distinct(source);
        }
        public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, INDEX index)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.ElementAt<TSource>(queryable, index);

            TSource item;
            IElementAt<TSource> elementAt = source as IElementAt<TSource>;
            if (source != null)
                if (elementAt.ElementAt(index, out item))
                    return item;

            Library.Collections.Generic.IVectorReadOnly<TSource> indexed1 = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
            if (indexed1 != null)
            {
                return indexed1[index];
            }

            Library.Collections.IVectorReadOnly indexed = source as Library.Collections.IVectorReadOnly;
            if (indexed != null)
            {
                return (TSource)indexed[index];
            }

            return System.Linq.Enumerable.ElementAt(source, (int)index);
        }
        public static TSource ElementAtOrDefault<TSource>(this IEnumerable<TSource> source, INDEX index)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.ElementAtOrDefault<TSource>(queryable, index);

            TSource item;
            IElementAt<TSource> elementAt = source as IElementAt<TSource>;
            if (source != null)
                if (elementAt.ElementAt(index, out item))
                    return item;

            Library.Collections.Generic.IVectorReadOnly<TSource> indexed1 = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
            if (indexed1 != null)
            {
                try
                {
                    return indexed1[index];
                }
                catch (IndexOutOfRangeException)
                {
                    return default(TSource);
                }
            }

            Library.Collections.IVectorReadOnly indexed = source as Library.Collections.IVectorReadOnly;
            if (indexed != null)
            {
                try
                {
                    return (TSource)indexed[index];
                }
                catch (IndexOutOfRangeException)
                {
                    return default(TSource);
                }
            }

            return System.Linq.Enumerable.ElementAtOrDefault(source, (int)index);
        }
        public static IEnumerable<TResult> Empty<TResult>()
        {
            return System.Linq.Enumerable.Empty<TResult>();
        }
        public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, TSource second)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Except<TSource>(queryable, second);

            IExcept<TSource> except = first as IExcept<TSource>;
            if (except != null)
                return except.Except(second);

            throw new NotImplementedException();
        }
        public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, TSource second, IEqualityComparer<TSource> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Except<TSource>(queryable, second, comparer);

            IExcept<TSource> except = first as IExcept<TSource>;
            if (except != null)
                return except.Except(second, comparer);

            throw new NotImplementedException();
        }
        public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Except<TSource>(queryable, second);

            IExcept<TSource> except = first as IExcept<TSource>;
            if (except != null)
                return except.Except(second);

            return System.Linq.Enumerable.Except(first, second);
        }
        public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Except<TSource>(queryable, second, comparer);

            IExcept<TSource> except = first as IExcept<TSource>;
            if (except != null)
                return except.Except(second, comparer);

            return System.Linq.Enumerable.Except(first, second, comparer);
        }
        public static TSource First<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.First<TSource>(queryable);

            return System.Linq.Enumerable.First(source);
        }
        public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.First<TSource>(queryable, x => predicate(x));

            return source.Where(predicate).First();
        }
        public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.FirstOrDefault<TSource>(queryable);

            TSource item;
            IFirst<TSource> first = source as IFirst<TSource>;
            if (first != null)
                return first.First(out item) ? item : default(TSource);

            return System.Linq.Enumerable.FirstOrDefault(source);
        }
        public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.FirstOrDefault<TSource>(queryable, x => predicate(x));

            return source.Where(predicate).FirstOrDefault();
        }
        public static IEnumerable<System.Linq.IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey>(queryable, x => keySelector(x));

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey>(keySelector);

            return System.Linq.Enumerable.GroupBy(source, keySelector);
        }
        public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey, TResult>(queryable, x => keySelector(x), (x, y) => resultSelector(x, y));

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey, TResult>(keySelector, resultSelector);

            return System.Linq.Enumerable.GroupBy(source, keySelector, resultSelector);
        }
        public static IEnumerable<System.Linq.IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey, TElement>(queryable, x => keySelector(x), x => elementSelector(x));

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey, TElement>(keySelector, elementSelector);

            return System.Linq.Enumerable.GroupBy(source, keySelector, elementSelector);
        }
        public static IEnumerable<System.Linq.IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey>(queryable, x => keySelector(x), comparer);

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey>(keySelector, comparer);

            return System.Linq.Enumerable.GroupBy(source, keySelector, comparer);
        }
        public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey, TResult>(queryable, x => keySelector(x), (x, y) => resultSelector(x, y), comparer);

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey, TResult>(keySelector, resultSelector, comparer);

            return System.Linq.Enumerable.GroupBy(source, keySelector, resultSelector, comparer);
        }
        public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(queryable, x => keySelector(x), x => elementSelector(x), (x, y) => resultSelector(x, y));

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey, TElement, TResult>(keySelector, elementSelector, resultSelector);

            return System.Linq.Enumerable.GroupBy(source, keySelector, elementSelector, resultSelector);
        }
        public static IEnumerable<System.Linq.IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey, TElement>(queryable, x => keySelector(x), x => elementSelector(x), comparer);

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey, TElement>(keySelector, elementSelector, comparer);

            return System.Linq.Enumerable.GroupBy(source, keySelector, elementSelector, comparer);
        }
        public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(queryable, x => keySelector(x), x => elementSelector(x), (x, y) => resultSelector(x, y), comparer);

            IGroupBy<TSource> groupby = source as IGroupBy<TSource>;
            if (groupby != null)
                return groupby.GroupBy<TKey, TElement, TResult>(keySelector, elementSelector, resultSelector, comparer);

            return System.Linq.Enumerable.GroupBy(source, keySelector, elementSelector, resultSelector, comparer);
        }

        // for when a 1 -> n exists on the keys to group items by, e.g. blogArticles.GroupByEach(n=>n.Categories)
        // for when an item may appear in multiple groupings in the output enumerable
        //public static IEnumerable<System.Linq.IGrouping<TKey, TSource>> GroupByEach<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TKey>> keySelector)
        //{
        //    throw new NotImplementedException();
        //}
        ////...
        //public static IEnumerable<System.Linq.IGrouping<TKey, TElement>> GroupByEach<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TKey>> keySelector, Func<TSource, TElement> elementSelector)
        //{
        //    throw new NotImplementedException();
        //}
        //public static IEnumerable<System.Linq.IGrouping<TKey, TSource>> GroupByEach<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TKey>> keySelector, IEqualityComparer<TKey> comparer)
        //{
        //    throw new NotImplementedException();
        //}
        ////...
        //public static IEnumerable<System.Linq.IGrouping<TKey, TElement>> GroupByEach<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TKey>> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        //{
        //    throw new NotImplementedException();
        //}

        public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector)
        {
            System.Linq.IQueryable<TOuter> queryable = outer as System.Linq.IQueryable<TOuter>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(queryable, inner, x => outerKeySelector(x), x => innerKeySelector(x), (x, y) => resultSelector(x, y));

            IGroupJoin<TOuter> groupJoin = outer as IGroupJoin<TOuter>;
            if (groupJoin != null)
                return groupJoin.GroupJoin<TInner, TKey, TResult>(inner, outerKeySelector, innerKeySelector, resultSelector);

            return System.Linq.Enumerable.GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector);
        }
        public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TOuter> queryable = outer as System.Linq.IQueryable<TOuter>;
            if (queryable != null)
                return Library.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(queryable, inner, x => outerKeySelector(x), x => innerKeySelector(x), (x, y) => resultSelector(x, y), comparer);

            IGroupJoin<TOuter> groupJoin = outer as IGroupJoin<TOuter>;
            if (groupJoin != null)
                return groupJoin.GroupJoin<TInner, TKey, TResult>(inner, outerKeySelector, innerKeySelector, resultSelector, comparer);

            return System.Linq.Enumerable.GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
        }
        public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Intersect<TSource>(queryable, second);

            IIntersect<TSource> intersect = first as IIntersect<TSource>;
            if (intersect != null)
                return intersect.Intersect(second);

            return System.Linq.Enumerable.Intersect(first, second);
        }
        public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Intersect<TSource>(queryable, second, comparer);

            IIntersect<TSource> intersect = first as IIntersect<TSource>;
            if (intersect != null)
                return intersect.Intersect(second, comparer);

            return System.Linq.Enumerable.Intersect(first, second, comparer);
        }
        public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector)
        {
            System.Linq.IQueryable<TOuter> queryable = outer as System.Linq.IQueryable<TOuter>;
            if (queryable != null)
                return Library.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(queryable, inner, x => outerKeySelector(x), x => innerKeySelector(x), (x, y) => resultSelector(x, y));

            IJoin<TOuter> join = outer as IJoin<TOuter>;
            if (join != null)
                return join.Join(inner, outerKeySelector, innerKeySelector, resultSelector);

            return System.Linq.Enumerable.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector);
        }
        public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TOuter> queryable = outer as System.Linq.IQueryable<TOuter>;
            if (queryable != null)
                return Library.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(queryable, inner, x => outerKeySelector(x), x => innerKeySelector(x), (x, y) => resultSelector(x, y), comparer);

            IJoin<TOuter> join = outer as IJoin<TOuter>;
            if (join != null)
                return join.Join(inner, outerKeySelector, innerKeySelector, resultSelector, comparer);

            return System.Linq.Enumerable.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
        }
        public static TSource Last<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Last<TSource>(queryable);

            TSource item;
            ILast<TSource> last = source as ILast<TSource>;
            if (last != null)
                if (last.Last(out item)) return item;

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
            {
                ulong count = countable.Count;
                if (count > 0)
                {
                    Library.Collections.Generic.IVectorReadOnly<TSource> vector = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
                    if (vector != null)
                    {
                        return vector[count - 1];
                    }
                    else
                    {
                        Library.Collections.IVectorReadOnly vector2 = source as Library.Collections.IVectorReadOnly;
                        if (vector != null)
                        {
                            return (TSource)vector[count - 1];
                        }
                    }
                }
            }

            return System.Linq.Enumerable.Last(source);
        }
        public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Last<TSource>(queryable, x => predicate(x));

            return source.Where(predicate).Last();
        }
        public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.LastOrDefault<TSource>(queryable);

            TSource item;
            ILast<TSource> last = source as ILast<TSource>;
            if (last != null)
                return (last.Last(out item)) ? item : default(TSource);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
            {
                ulong count = countable.Count;
                if (count > 0)
                {
                    Library.Collections.Generic.IVectorReadOnly<TSource> vector = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
                    if (vector != null)
                    {
                        return vector[count - 1];
                    }
                    else
                    {
                        Library.Collections.IVectorReadOnly vector2 = source as Library.Collections.IVectorReadOnly;
                        if (vector != null)
                        {
                            return (TSource)vector[count - 1];
                        }
                    }
                }
            }

            return System.Linq.Enumerable.LastOrDefault(source);
        }
        public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.LastOrDefault<TSource>(queryable, x => predicate(x));

            TSource item;
            ILast<TSource> last = source as ILast<TSource>;
            if (last != null)
                return (last.Last(out item)) ? item : default(TSource);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
            {
                ulong count = countable.Count;
                if (count > 0)
                {
                    Library.Collections.Generic.IVectorReadOnly<TSource> vector = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
                    if (vector != null)
                    {
                        return vector[count - 1];
                    }
                    else
                    {
                        Library.Collections.IVectorReadOnly vector2 = source as Library.Collections.IVectorReadOnly;
                        if (vector != null)
                        {
                            return (TSource)vector[count - 1];
                        }
                    }
                }
            }

            return source.Where(predicate).LastOrDefault();
        }
        public static ulong LongCount<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return (ulong)Library.Linq.Queryable.LongCount<TSource>(queryable);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
                return countable.Count;

            return (ulong)System.Linq.Enumerable.LongCount(source);
        }
        public static ulong LongCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return (ulong)Library.Linq.Queryable.LongCount<TSource>(queryable, x => predicate(x));

            return source.Where(predicate).LongCount();
        }
        public static decimal? Max(this IEnumerable<decimal?> source)
        {
            System.Linq.IQueryable<decimal?> queryable = source as System.Linq.IQueryable<decimal?>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<decimal?>(queryable);

            decimal? item;
            IMaximum<decimal?> maximum = source as IMaximum<decimal?>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static decimal Max(this IEnumerable<decimal> source)
        {
            System.Linq.IQueryable<decimal> queryable = source as System.Linq.IQueryable<decimal>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<decimal>(queryable);

            decimal item;
            IMaximum<decimal> maximum = source as IMaximum<decimal>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static double? Max(this IEnumerable<double?> source)
        {
            System.Linq.IQueryable<double?> queryable = source as System.Linq.IQueryable<double?>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<double?>(queryable);

            double? item;
            IMaximum<double?> maximum = source as IMaximum<double?>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static double Max(this IEnumerable<double> source)
        {
            System.Linq.IQueryable<double> queryable = source as System.Linq.IQueryable<double>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<double>(queryable);

            double item;
            IMaximum<double> maximum = source as IMaximum<double>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static float? Max(this IEnumerable<float?> source)
        {
            System.Linq.IQueryable<float?> queryable = source as System.Linq.IQueryable<float?>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<float?>(queryable);

            float? item;
            IMaximum<float?> maximum = source as IMaximum<float?>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static float Max(this IEnumerable<float> source)
        {
            System.Linq.IQueryable<float> queryable = source as System.Linq.IQueryable<float>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<float>(queryable);

            float item;
            IMaximum<float> maximum = source as IMaximum<float>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static int? Max(this IEnumerable<int?> source)
        {
            System.Linq.IQueryable<int?> queryable = source as System.Linq.IQueryable<int?>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<int?>(queryable);

            int? item;
            IMaximum<int?> maximum = source as IMaximum<int?>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static int Max(this IEnumerable<int> source)
        {
            System.Linq.IQueryable<int> queryable = source as System.Linq.IQueryable<int>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<int>(queryable);

            int item;
            IMaximum<int> maximum = source as IMaximum<int>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static long? Max(this IEnumerable<long?> source)
        {
            System.Linq.IQueryable<long?> queryable = source as System.Linq.IQueryable<long?>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<long?>(queryable);
            
            long? item;
            IMaximum<long?> maximum = source as IMaximum<long?>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static long Max(this IEnumerable<long> source)
        {
            System.Linq.IQueryable<long> queryable = source as System.Linq.IQueryable<long>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<long>(queryable);

            long item;
            IMaximum<long> maximum = source as IMaximum<long>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static TSource Max<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max<TSource>(queryable);

            TSource item;
            IMaximum<TSource> maximum = source as IMaximum<TSource>;
            if (maximum != null)
                if (maximum.Maximum(out item)) return item;

            return System.Linq.Enumerable.Max(source);
        }
        public static decimal? Max<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static decimal Max<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static double? Max<TSource>(this IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static double Max<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static float? Max<TSource>(this IEnumerable<TSource> source, Func<TSource, float?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static float Max<TSource>(this IEnumerable<TSource> source, Func<TSource, float> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static int? Max<TSource>(this IEnumerable<TSource> source, Func<TSource, int?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static int Max<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static long? Max<TSource>(this IEnumerable<TSource> source, Func<TSource, long?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static long Max<TSource>(this IEnumerable<TSource> source, Func<TSource, long> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static TResult Max<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Max(queryable, x => selector(x));

            return System.Linq.Enumerable.Max(source, selector);
        }
        public static decimal? Min(this IEnumerable<decimal?> source)
        {
            System.Linq.IQueryable<decimal?> queryable = source as System.Linq.IQueryable<decimal?>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<decimal?>(queryable);

            decimal? item;
            IMinimum<decimal?> minimum = source as IMinimum<decimal?>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static decimal Min(this IEnumerable<decimal> source)
        {
            System.Linq.IQueryable<decimal> queryable = source as System.Linq.IQueryable<decimal>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<decimal>(queryable);

            decimal item;
            IMinimum<decimal> minimum = source as IMinimum<decimal>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static double? Min(this IEnumerable<double?> source)
        {
            System.Linq.IQueryable<double?> queryable = source as System.Linq.IQueryable<double?>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<double?>(queryable);

            double? item;
            IMinimum<double?> minimum = source as IMinimum<double?>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static double Min(this IEnumerable<double> source)
        {
            System.Linq.IQueryable<double> queryable = source as System.Linq.IQueryable<double>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<double>(queryable);

            double item;
            IMinimum<double> minimum = source as IMinimum<double>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static float? Min(this IEnumerable<float?> source)
        {
            System.Linq.IQueryable<float?> queryable = source as System.Linq.IQueryable<float?>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<float?>(queryable);

            float? item;
            IMinimum<float?> minimum = source as IMinimum<float?>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static float Min(this IEnumerable<float> source)
        {
            System.Linq.IQueryable<float> queryable = source as System.Linq.IQueryable<float>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<float>(queryable);

            float item;
            IMinimum<float> minimum = source as IMinimum<float>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static int? Min(this IEnumerable<int?> source)
        {
            System.Linq.IQueryable<int?> queryable = source as System.Linq.IQueryable<int?>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<int?>(queryable);

            int? item;
            IMinimum<int?> minimum = source as IMinimum<int?>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static int Min(this IEnumerable<int> source)
        {
            System.Linq.IQueryable<int> queryable = source as System.Linq.IQueryable<int>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<int>(queryable);

            int item;
            IMinimum<int> minimum = source as IMinimum<int>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static long? Min(this IEnumerable<long?> source)
        {
            System.Linq.IQueryable<long?> queryable = source as System.Linq.IQueryable<long?>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<long?>(queryable);

            long? item;
            IMinimum<long?> minimum = source as IMinimum<long?>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static long Min(this IEnumerable<long> source)
        {
            System.Linq.IQueryable<long> queryable = source as System.Linq.IQueryable<long>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<long>(queryable);

            long item;
            IMinimum<long> minimum = source as IMinimum<long>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static TSource Min<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min<TSource>(queryable);

            TSource item;
            IMinimum<TSource> minimum = source as IMinimum<TSource>;
            if (minimum != null)
                if (minimum.Minimum(out item)) return item;

            return System.Linq.Enumerable.Min(source);
        }
        public static decimal? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static decimal Min<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static double? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static double Min<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static float? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, float?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static float Min<TSource>(this IEnumerable<TSource> source, Func<TSource, float> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static int? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, int?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static int Min<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static long? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, long?> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static long Min<TSource>(this IEnumerable<TSource> source, Func<TSource, long> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static TResult Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Min(queryable, x => selector(x));

            return System.Linq.Enumerable.Min(source, selector);
        }
        public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
        {
            System.Linq.IQueryable queryable = source as System.Linq.IQueryable;
            if (queryable != null)
                return Library.Linq.Queryable.OfType<TResult>(queryable);

            IOfType oftype = source as IOfType;
            if (oftype != null)
                return oftype.OfType<TResult>();

            return System.Linq.Enumerable.OfType<TResult>(source);
        }
        public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.OrderBy<TSource, TKey>(queryable, x => keySelector(x));

            IOrderBy<TSource> orderBy = source as IOrderBy<TSource>;
            if (orderBy != null)
                return orderBy.OrderBy<TKey>(keySelector);

            IOrderedEnumerable<TSource> orderedEnumerable = source as IOrderedEnumerable<TSource>;
            if (orderedEnumerable != null)
            {
                var input = orderedEnumerable.Input;
                if (input != null && !object.ReferenceEquals(orderedEnumerable, input))
                {
                    return ((IEnumerable<TSource>)input).OrderBy(keySelector);
                }
            }

            return OrderByEnumerable<TSource, TKey>.Create(source, (x) => keySelector(x));
        }
        public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.OrderBy<TSource, TKey>(queryable, x => keySelector(x), comparer);

            IOrderBy<TSource> orderBy = source as IOrderBy<TSource>;
            if (orderBy != null)
                return orderBy.OrderBy<TKey>(keySelector, comparer);

            IOrderedEnumerable<TSource> orderedEnumerable = source as IOrderedEnumerable<TSource>;
            if (orderedEnumerable != null)
            {
                var input = orderedEnumerable.Input;
                if (input != null && !object.ReferenceEquals(orderedEnumerable, input))
                {
                    return ((IEnumerable<TSource>)input).OrderBy(keySelector, comparer);
                }
            }

            return OrderByEnumerable<TSource, TKey>.Create(source, (x) => keySelector(x), comparer);
        }
        public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.OrderByDescending<TSource, TKey>(queryable, x => keySelector(x));

            IOrderBy<TSource> orderBy = source as IOrderBy<TSource>;
            if (orderBy != null)
                return orderBy.OrderByDescending<TKey>(keySelector);

            IOrderedEnumerable<TSource> orderedEnumerable = source as IOrderedEnumerable<TSource>;
            if (orderedEnumerable != null)
            {
                var input = orderedEnumerable.Input;
                if (input != null && !object.ReferenceEquals(orderedEnumerable, input))
                {
                    return ((IEnumerable<TSource>)input).OrderByDescending(keySelector);
                }
            }

            return OrderByDescendingEnumerable<TSource, TKey>.Create(source, (x) => keySelector(x));
        }
        public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.OrderByDescending<TSource, TKey>(queryable, x => keySelector(x), comparer);

            IOrderBy<TSource> orderBy = source as IOrderBy<TSource>;
            if (orderBy != null)
                return orderBy.OrderByDescending<TKey>(keySelector, comparer);

            IOrderedEnumerable<TSource> orderedEnumerable = source as IOrderedEnumerable<TSource>;
            if (orderedEnumerable != null)
            {
                var input = orderedEnumerable.Input;
                if (input != null && !object.ReferenceEquals(orderedEnumerable, input))
                {
                    return ((IEnumerable<TSource>)input).OrderByDescending(keySelector, comparer);
                }
            }

            return OrderByDescendingEnumerable<TSource, TKey>.Create(source, (x) => keySelector(x), comparer);
        }
        public static IEnumerable<INDEX> Range(INDEX start, INDEX count)
        {
            if (count == 0) return Empty<INDEX>();
            return new RangeEnumerable(start, count);
        }
        public static IEnumerable<TResult> Repeat<TResult>(TResult element, INDEX count)
        {
            return System.Linq.Enumerable.Repeat(element, (int)count);
        }
        public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Reverse<TSource>(queryable);

            IReverse<TSource> reverse = source as IReverse<TSource>;
            if (reverse != null)
                return reverse.Reverse();

            return System.Linq.Enumerable.Reverse(source);
        }
        public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Select<TSource, TResult>(queryable, x => selector(x));

            ISelect<TSource> s = source as ISelect<TSource>;
            if (s != null)
                return s.Select<TResult>(selector);

            return System.Linq.Enumerable.Select(source, selector);
        }
        public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, INDEX, TResult> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Select<TSource, TResult>(queryable, (x, n) => selector(x, (INDEX)n));

            ISelect<TSource> s = source as ISelect<TSource>;
            if (s != null)
                return s.Select<TResult>(selector);

            return System.Linq.Enumerable.Select(source, (TSource a, int b) => selector(a, (INDEX)b));
        }
        public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SelectMany<TSource, TResult>(queryable, x => selector(x));

            ISelectMany<TSource> selectMany = source as ISelectMany<TSource>;
            if (selectMany != null)
                return selectMany.SelectMany<TResult>(selector);

            return System.Linq.Enumerable.SelectMany(source, selector);
        }
        public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, INDEX, IEnumerable<TResult>> selector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SelectMany<TSource, TResult>(queryable, (x, n) => selector(x, n));

            ISelectMany<TSource> selectMany = source as ISelectMany<TSource>;
            if (selectMany != null)
                return selectMany.SelectMany<TResult>(selector);

            return System.Linq.Enumerable.SelectMany(source, (TSource a, int b) => selector(a, (INDEX)b));
        }
        public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(queryable, x => collectionSelector(x), (x, c) => resultSelector(x, c));

            ISelectMany<TSource> selectMany = source as ISelectMany<TSource>;
            if (selectMany != null)
                return selectMany.SelectMany<TCollection, TResult>(collectionSelector, resultSelector);

            return System.Linq.Enumerable.SelectMany(source, collectionSelector, resultSelector);
        }
        public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, INDEX, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(queryable, (x, n) => collectionSelector(x, n), (x, c) => resultSelector(x, c));

            ISelectMany<TSource> selectMany = source as ISelectMany<TSource>;
            if (selectMany != null)
                return selectMany.SelectMany<TCollection, TResult>(collectionSelector, resultSelector);

            return System.Linq.Enumerable.SelectMany(source, (TSource a, int b) => collectionSelector(a, (INDEX)b), resultSelector);
        }
        public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            return System.Linq.Enumerable.SequenceEqual(first, second);
        }
        public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
        {
            return System.Linq.Enumerable.SequenceEqual(first, second, comparer);
        }
        public static TSource Single<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Single<TSource>(queryable);

            TSource item;
            ISingle<TSource> single = source as ISingle<TSource>;
            if (single != null)
                if (single.Single(out item)) return item;

            return System.Linq.Enumerable.Single(source);
        }
        public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Single<TSource>(queryable, x => predicate(x));

            return source.Where(predicate).Single();
        }
        public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SingleOrDefault<TSource>(queryable);

            TSource item;
            ISingle<TSource> single = source as ISingle<TSource>;
            if (single != null)
                return (single.Single(out item)) ? item : default(TSource);

            return System.Linq.Enumerable.SingleOrDefault(source);
        }
        public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SingleOrDefault<TSource>(queryable, x => predicate(x));

            return System.Linq.Enumerable.SingleOrDefault(source, predicate);
        }
        public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, INDEX count)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Skip<TSource>(queryable, count);

            ISkip<TSource> skip = source as ISkip<TSource>;
            if (skip != null)
                return skip.Skip(count);

            return System.Linq.Enumerable.Skip(source, (int)count);
        }
        public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SkipWhile<TSource>(queryable, x => predicate(x));

            ISkipWhile<TSource> skipwhile = source as ISkipWhile<TSource>;
            if (skipwhile != null)
                return skipwhile.SkipWhile(predicate);

            return System.Linq.Enumerable.SkipWhile(source, predicate);
        }
        public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, INDEX, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.SkipWhile<TSource>(queryable, (x, n) => predicate(x, n));

            ISkipWhile<TSource> skipwhile = source as ISkipWhile<TSource>;
            if (skipwhile != null)
                return skipwhile.SkipWhile(predicate);

            return System.Linq.Enumerable.SkipWhile(source, (TSource a, int b) => predicate(a, (INDEX)b));
        }
        public static decimal? Sum(this IEnumerable<decimal?> source)
        {
            System.Linq.IQueryable<decimal?> queryable = source as System.Linq.IQueryable<decimal?>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<decimal?>(queryable, x => x);

            decimal? value;
            ISum<decimal?> summable = source as ISum<decimal?>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static decimal Sum(this IEnumerable<decimal> source)
        {
            System.Linq.IQueryable<decimal> queryable = source as System.Linq.IQueryable<decimal>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<decimal>(queryable, x => x);

            decimal value;
            ISum<decimal> summable = source as ISum<decimal>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static double? Sum(this IEnumerable<double?> source)
        {
            System.Linq.IQueryable<double?> queryable = source as System.Linq.IQueryable<double?>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<double?>(queryable, x => x);

            double? value;
            ISum<double?> summable = source as ISum<double?>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static double Sum(this IEnumerable<double> source)
        {
            System.Linq.IQueryable<double> queryable = source as System.Linq.IQueryable<double>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<double>(queryable, x => x);

            double value;
            ISum<double> summable = source as ISum<double>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static float? Sum(this IEnumerable<float?> source)
        {
            System.Linq.IQueryable<float?> queryable = source as System.Linq.IQueryable<float?>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<float?>(queryable, x => x);

            float? value;
            ISum<float?> summable = source as ISum<float?>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static float Sum(this IEnumerable<float> source)
        {
            System.Linq.IQueryable<float> queryable = source as System.Linq.IQueryable<float>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<float>(queryable, x => x);

            float value;
            ISum<float> summable = source as ISum<float>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static int? Sum(this IEnumerable<int?> source)
        {
            System.Linq.IQueryable<int?> queryable = source as System.Linq.IQueryable<int?>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<int?>(queryable, x => x);

            int? value;
            ISum<int?> summable = source as ISum<int?>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static int Sum(this IEnumerable<int> source)
        {
            System.Linq.IQueryable<int> queryable = source as System.Linq.IQueryable<int>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<int>(queryable, x => x);
            
            int value;
            ISum<int> summable = source as ISum<int>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static long? Sum(this IEnumerable<long?> source)
        {
            System.Linq.IQueryable<long?> queryable = source as System.Linq.IQueryable<long?>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<long?>(queryable, x => x);

            long? value;
            ISum<long?> summable = source as ISum<long?>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static long Sum(this IEnumerable<long> source)
        {
            System.Linq.IQueryable<long> queryable = source as System.Linq.IQueryable<long>;
            if (queryable != null)
                return Library.Linq.Queryable.Sum<long>(queryable, x => x);

            long value;
            ISum<long> summable = source as ISum<long>;
            if (summable != null)
                if (summable.Sum(out value))
                    return value;

            return System.Linq.Enumerable.Sum(source);
        }
        public static decimal? Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static decimal Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static double? Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static double Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static float? Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, float?> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static float Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, float> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static int? Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, int?> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static int Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static long? Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, long?> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static long Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, long> selector)
        {
            return System.Linq.Enumerable.Sum(source, selector);
        }
        public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, INDEX count)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Take<TSource>(queryable, count);

            ITake<TSource> take = source as ITake<TSource>;
            if (take != null)
                return take.Take(count);

            return System.Linq.Enumerable.Take(source, (int)count);
        }
        public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.TakeWhile<TSource>(queryable, x => predicate(x));

            ITakeWhile<TSource> takewhile = source as ITakeWhile<TSource>;
            if (takewhile != null)
                return takewhile.TakeWhile(predicate);

            return System.Linq.Enumerable.TakeWhile(source, predicate);
        }
        public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, INDEX, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.TakeWhile<TSource>(queryable, (x, n) => predicate(x, n));

            ITakeWhile<TSource> takewhile = source as ITakeWhile<TSource>;
            if (takewhile != null)
                return takewhile.TakeWhile(predicate);

            return System.Linq.Enumerable.TakeWhile(source, (TSource a, int b) => predicate(a, (INDEX)b));
        }
        public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            Library.Linq.IOrderedQueryable<TSource> queryable = source as Library.Linq.IOrderedQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.ThenBy<TSource, TKey>(queryable, x => keySelector(x));

            IThenBy<TSource> thenBy = source as IThenBy<TSource>;
            if (thenBy != null)
                return thenBy.ThenBy<TKey>(keySelector);

            return CreateThenBy<TSource, TKey>(source, keySelector);
        }
        public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            Library.Linq.IOrderedQueryable<TSource> queryable = source as Library.Linq.IOrderedQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.ThenBy<TSource, TKey>(queryable, x => keySelector(x), comparer);

            IThenBy<TSource> thenBy = source as IThenBy<TSource>;
            if (thenBy != null)
                return thenBy.ThenBy<TKey>(keySelector, comparer);

            return CreateThenBy<TSource, TKey>(source, keySelector, comparer);
        }
        public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            Library.Linq.IOrderedQueryable<TSource> queryable = source as Library.Linq.IOrderedQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.ThenByDescending<TSource, TKey>(queryable, x => keySelector(x));

            IThenBy<TSource> thenBy = source as IThenBy<TSource>;
            if (thenBy != null)
                return thenBy.ThenByDescending<TKey>(keySelector);

            return CreateThenByDescending<TSource, TKey>(source, keySelector);

            //var comparison = source.Comparison;
            //var p0 = comparison.Parameters[0];
            //var p1 = comparison.Parameters[1];
            //ParameterExpression old_comparison = Expression.Variable(typeof(int));
            //var x_compare_y = Expression.Invoke(comparison, p0, p1);
            //var assign = Expression.Assign(old_comparison, x_compare_y);
            //var x_equals_y = Expression.Equal(assign, Expression.Constant(0));
            //Type type = typeof(Comparer<TKey>);
            //var new_comparison = Expression.Call(Expression.Call(null, type.GetProperty("Default").GetGetMethod()), type.GetMethod("Compare"), p0, p1);

            //var condition = Expression.Condition(x_equals_y, Expression.Negate(new_comparison), old_comparison);
            //var lambda = Expression.Lambda<Func<TSource, TSource, int>>(condition, p0, p1);

            //throw new NotImplementedException();
        }
        public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            Library.Linq.IOrderedQueryable<TSource> queryable = source as Library.Linq.IOrderedQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.ThenByDescending<TSource, TKey>(queryable, x => keySelector(x), comparer);

            IThenBy<TSource> thenBy = source as IThenBy<TSource>;
            if (thenBy != null)
                return thenBy.ThenByDescending<TKey>(keySelector, comparer);

            return CreateThenByDescending<TSource, TKey>(source, keySelector, comparer);

            //var comparison = source.Comparison;
            //var p0 = comparison.Parameters[0];
            //var p1 = comparison.Parameters[1];
            //ParameterExpression old_comparison = Expression.Variable(typeof(int));
            //var x_compare_y = Expression.Invoke(comparison, p0, p1);
            //var assign = Expression.Assign(old_comparison, x_compare_y);
            //var x_equals_y = Expression.Equal(assign, Expression.Constant(0));
            //var new_comparison = Expression.Call(Expression.Constant(comparer), typeof(IComparer<TKey>).GetMethod("Compare"), p0, p1);

            //var condition = Expression.Condition(x_equals_y, Expression.Negate(new_comparison), old_comparison);
            //var lambda = Expression.Lambda<Func<TSource, TSource, int>>(condition, p0, p1);

            //throw new NotImplementedException();
        }
        public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
        {
            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
            {
                Library.Collections.Specialized.ICopyToArray<TSource> copyto = source as Library.Collections.Specialized.ICopyToArray<TSource>;
                if (copyto != null)
                {
                    INDEX count = countable.Count;
                    TSource[] array = new TSource[count];
                    copyto.CopyTo(0, array, 0, count);
                    return array;
                }
            }

            return System.Linq.Enumerable.ToArray(source);
        }
        public static Library.Collections.Generic.IDictionaryReadOnly<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            throw new NotImplementedException();
        }
        public static Library.Collections.Generic.IDictionaryReadOnly<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            throw new NotImplementedException();
        }
        public static Library.Collections.Generic.IDictionaryReadOnly<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            throw new NotImplementedException();
        }
        public static Library.Collections.Generic.IDictionaryReadOnly<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            throw new NotImplementedException();
        }
        public static Library.Collections.Generic.IVectorReadOnly<TSource> ToVector<TSource>(this IEnumerable<TSource> source)
        {
            throw new NotImplementedException();
        }
        public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            throw new NotImplementedException();
        }
        public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            throw new NotImplementedException();
        }
        public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            throw new NotImplementedException();
        }
        public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            throw new NotImplementedException();
        }
        public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Union<TSource>(queryable, second);

            IUnion<TSource> union = first as IUnion<TSource>;
            if (union != null)
                return union.Union(second);

            return System.Linq.Enumerable.Union(first, second);
        }
        public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
        {
            System.Linq.IQueryable<TSource> queryable = first as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Union<TSource>(queryable, second, comparer);

            IUnion<TSource> union = first as IUnion<TSource>;
            if (union != null)
                return union.Union(second, comparer);

            return System.Linq.Enumerable.Union(first, second, comparer);
        }
        public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Where<TSource>(queryable, (x) => predicate(x));

            IWhere<TSource> where = source as IWhere<TSource>;
            if (where != null)
                return where.Where(predicate);

            return System.Linq.Enumerable.Where(source, predicate);
        }
        public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, INDEX, bool> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Library.Linq.Queryable.Where<TSource>(queryable, (a, b) => predicate(a, b));

            IWhere<TSource> where = source as IWhere<TSource>;
            if (where != null)
                return where.Where(predicate);

            return System.Linq.Enumerable.Where(source, (TSource a, int b) => predicate(a, (INDEX)b));
        }
        public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
        {
            System.Linq.IQueryable<TFirst> queryable = first as System.Linq.IQueryable<TFirst>;
            if (queryable != null)
                return Library.Linq.Queryable.Zip<TFirst, TSecond, TResult>(queryable, second, (x, y) => resultSelector(x, y));

            IZip<TFirst> zip = first as IZip<TFirst>;
            if (zip != null)
                return zip.Zip(second, resultSelector);

            return System.Linq.Enumerable.Zip(first, second, resultSelector);
        }
    }
}
